#include "BindNetwork.hpp"

using namespace luabind;
namespace bind
{
	namespace SFML
	{
		namespace network
		{		
			void BFtp(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Ftp>("Ftp")
							.def("Connect", &sf::Ftp::Connect)
							.def("Disconnect", &sf::Ftp::Disconnect)
							.def("Login", (sf::Ftp::Response(sf::Ftp::*)())&sf::Ftp::Login)
							.def("Login", (sf::Ftp::Response(sf::Ftp::*)(const std::string&, const std::string&))&sf::Ftp::Login)
							.def("KeepAlive", &sf::Ftp::KeepAlive)
							.def("GetWorkingDirectory", &sf::Ftp::GetWorkingDirectory)
							.def("GetDirectoryListing", &sf::Ftp::GetDirectoryListing)
							.def("ChangeDirectory", &sf::Ftp::ChangeDirectory)
							.def("ParentDirectory", &sf::Ftp::ParentDirectory)
							.def("CreateDirectory", &sf::Ftp::CreateDirectory)
							.def("DeleteDirectory", &sf::Ftp::DeleteDirectory)
							.def("RenameFile", &sf::Ftp::RenameFile)
							.def("DeleteFile", &sf::Ftp::DeleteFile)
							.def("Download", &sf::Ftp::Download)
							.def("Upload", &sf::Ftp::Upload),

						class_<sf::Ftp::Response>("Ftp.Response")
							.def(constructor<sf::Ftp::Response::Status, const std::string&>())
							.def("IsOk", &sf::Ftp::Response::IsOk)
							.def("GetStatus", &sf::Ftp::Response::GetStatus)
							.def("GetMessage", &sf::Ftp::Response::GetMessage),								

						class_<sf::Ftp::DirectoryResponse, bases<sf::Ftp::Response> >("Ftp.DirectoryResponse")
							.def(constructor<const sf::Ftp::Response&>())
							.def("GetDirectory", &sf::Ftp::DirectoryResponse::GetDirectory),

						class_<sf::Ftp::ListingResponse, bases<sf::Ftp::Response> >("Ftp.ListingResponse")
							.def(constructor<const sf::Ftp::Response&, const std::vector<char>&>())
							.def("GetFilenames", &sf::Ftp::ListingResponse::GetFilenames, return_stl_iterator)
					];

				object transfermode = newtable(lua);
				transfermode["Binary"] = sf::Ftp::TransferMode::Binary;
				transfermode["Ascii"] = sf::Ftp::TransferMode::Ascii;
				transfermode["Ebcdic"] = sf::Ftp::TransferMode::Ebcdic;
				globals(lua)[ns.c_str()]["Ftp"]["TransferMode"] = transfermode;

				object status = newtable(lua);
				status["RestartMarkerReply"] = sf::Ftp::Response::RestartMarkerReply;
				status["ServiceReadySoon"] = sf::Ftp::Response::ServiceReadySoon;
				status["DataConnectionAlreadyOpened"] = sf::Ftp::Response::DataConnectionAlreadyOpened;
				status["OpeningDataConnection"] = sf::Ftp::Response::OpeningDataConnection;
				status["Ok"] = sf::Ftp::Response::Ok;
				status["PointlessCommand"] = sf::Ftp::Response::PointlessCommand;
				status["SystemStatus"] = sf::Ftp::Response::SystemStatus;
				status["DirectoryStatus"] = sf::Ftp::Response::DirectoryStatus;
				status["FileStatus"] = sf::Ftp::Response::FileStatus;
				status["HelpMessage"] = sf::Ftp::Response::HelpMessage;
				status["SystemType"] = sf::Ftp::Response::SystemType;
				status["ServiceReady"] = sf::Ftp::Response::ServiceReady;
				status["ClosingConnection"] = sf::Ftp::Response::ClosingConnection;
				status["DataConnectionOpened"] = sf::Ftp::Response::DataConnectionOpened;
				status["ClosingDataConnection"] = sf::Ftp::Response::ClosingDataConnection;
				status["EnteringPassiveMode"] = sf::Ftp::Response::EnteringPassiveMode;
				status["LoggedIn"] = sf::Ftp::Response::LoggedIn;
				status["FileActionOk"] = sf::Ftp::Response::FileActionOk;
				status["DirectoryOk"] = sf::Ftp::Response::DirectoryOk;
				status["NeedPassword"] = sf::Ftp::Response::NeedPassword;
				status["NeedAccountToLogIn"] = sf::Ftp::Response::NeedAccountToLogIn;
				status["NeedInformation"] = sf::Ftp::Response::NeedInformation;
				status["ServiceUnavailable"] = sf::Ftp::Response::ServiceUnavailable;
				status["DataConnectionUnavailable"] = sf::Ftp::Response::DataConnectionUnavailable;
				status["TransferAborted"] = sf::Ftp::Response::TransferAborted;
				status["FileActionAborted"] = sf::Ftp::Response::FileActionAborted;
				status["LocalError"] = sf::Ftp::Response::LocalError;
				status["InsufficientStorageSpace"] = sf::Ftp::Response::InsufficientStorageSpace;
				status["CommandUnknown"] = sf::Ftp::Response::CommandUnknown;
				status["ParametersUnknown"] = sf::Ftp::Response::ParametersUnknown;
				status["CommandNotImplemented"] = sf::Ftp::Response::CommandNotImplemented;
				status["BadCommandSequence"] = sf::Ftp::Response::BadCommandSequence;
				status["ParameterNotImplemented"] = sf::Ftp::Response::ParameterNotImplemented;
				status["NotLoggedIn"] = sf::Ftp::Response::NotLoggedIn;
				status["NeedAccountToStore"] = sf::Ftp::Response::NeedAccountToStore;
				status["FileUnavailable"] = sf::Ftp::Response::FileUnavailable;
				status["PageTypeUnknown"] = sf::Ftp::Response::PageTypeUnknown;
				status["NotEnoughMemory"] = sf::Ftp::Response::NotEnoughMemory;
				status["FilenameNotAllowed"] = sf::Ftp::Response::FilenameNotAllowed;
				status["InvalidResponse"] = sf::Ftp::Response::InvalidResponse;
				status["ConnectionFailed"] = sf::Ftp::Response::ConnectionFailed;
				status["ConnectionClosed"] = sf::Ftp::Response::ConnectionClosed;
				status["InvalidFile"] = sf::Ftp::Response::InvalidFile;
				globals(lua)[ns.c_str()]["Ftp"]["Response"] = newtable(lua);
				globals(lua)[ns.c_str()]["Ftp"]["Response"]["Status"] = status;
			}
				
			void BHttp(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Http::Request>("Http.Request")
							.def(constructor<const std::string&, sf::Http::Request::Method, const std::string&>())
							.def("SetField", &sf::Http::Request::SetField)
							.def("SetMethod", &sf::Http::Request::SetMethod)
							.def("SetUri", &sf::Http::Request::SetUri)
							.def("SetHttpVersion", &sf::Http::Request::SetHttpVersion)
							.def("SetBody", &sf::Http::Request::SetBody),

						class_<sf::Http::Response>("Http.Response")
							.def(constructor<>())
							.def("GetField", &sf::Http::Response::GetField)
							.def("GetStatus", &sf::Http::Response::GetStatus)
							.def("GetMajorHttpVersion", &sf::Http::Response::GetMajorHttpVersion)
							.def("GetMinorHttpVersion", &sf::Http::Response::GetMinorHttpVersion)
							.def("GetBody", &sf::Http::Response::GetBody),

						class_<sf::Http>("Http")
							.def(constructor<>())
							.def(constructor<const std::string&, unsigned short>())
							.def("SetHost", &sf::Http::SetHost)
							.def("SendRequest", &sf::Http::SendRequest)
					];

				object method = newtable(lua);
				method["Get"] = sf::Http::Request::Get;
				method["Post"] = sf::Http::Request::Post;
				method["Head"] = sf::Http::Request::Head;
				globals(lua)[ns.c_str()]["Http"]["Request"] = newtable(lua);
				globals(lua)[ns.c_str()]["Http"]["Request"]["Method"] = method;

				object status = newtable(lua);
				status["Ok"] = sf::Http::Response::Ok;
				status["Created"] = sf::Http::Response::Created;
				status["Accepted"] = sf::Http::Response::Accepted;
				status["NoContent"] = sf::Http::Response::NoContent;
				status["ResetContent"] = sf::Http::Response::ResetContent;
				status["PartialContent"] = sf::Http::Response::PartialContent;
				status["MultipleChoices"] = sf::Http::Response::MultipleChoices;
				status["MovedPermanently"] = sf::Http::Response::MovedPermanently;
				status["MovedTemporarily"] = sf::Http::Response::MovedTemporarily;
				status["NotModified"] = sf::Http::Response::NotModified;
				status["BadRequest"] = sf::Http::Response::BadRequest;
				status["Unauthorized"] = sf::Http::Response::Unauthorized;
				status["Forbidden"] = sf::Http::Response::Forbidden;
				status["NotFound"] = sf::Http::Response::NotFound;
				status["RangeNotSatisfiable"] = sf::Http::Response::RangeNotSatisfiable;
				status["InternalServerError"] = sf::Http::Response::InternalServerError;
				status["NotImplemented"] = sf::Http::Response::NotImplemented;
				status["BadGateway"] = sf::Http::Response::BadGateway;
				status["ServiceNotAvailable"] = sf::Http::Response::ServiceNotAvailable;
				status["GatewayTimeout"] = sf::Http::Response::GatewayTimeout;
				status["VersionNotSupported"] = sf::Http::Response::VersionNotSupported;
				status["InvalidResponse"] = sf::Http::Response::InvalidResponse;
				status["ConnectionFailed"] = sf::Http::Response::ConnectionFailed;
				globals(lua)[ns.c_str()]["Http"]["Response"] = newtable(lua);
				globals(lua)[ns.c_str()]["Http"]["Response"]["Status"] = status;
			}
				
			void BIpAddress(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::IpAddress>("IpAddress")
							.def(constructor<>())
							.def(constructor<const std::string&>())
							.def(constructor<const char*>())
							.def(constructor<sf::Uint8, sf::Uint8, sf::Uint8, sf::Uint8>())
							.def(constructor<sf::Uint32>())
							.def("GetLocalAddress", &sf::IpAddress::GetLocalAddress)
							.def("GetPublicAddress", &sf::IpAddress::GetPublicAddress)
							.def("ToString", &sf::IpAddress::ToString)
							.def("ToInteger", &sf::IpAddress::ToInteger)
							.def(const_self == sf::IpAddress())
							.def(const_self < sf::IpAddress())
							.def(const_self <= sf::IpAddress())
					];

				LUA_CONST_START(lua, sf::IpAddress)
				LUA_CONST(sf::IpAddress, None)
				LUA_CONST(sf::IpAddress, LocalHost)
				LUA_CONST_END
			}
				
			void BPacket(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Packet>("Packet")
							.def(constructor<>())
							.def("Append", &sf::Packet::Append)
							.def("Clear", &sf::Packet::Clear)
							.def("GetData", &sf::Packet::GetData)
							.def("GetDataSize", &sf::Packet::GetDataSize)
							.def("EndOfPacket", &sf::Packet::EndOfPacket)
							.def(self + bool())
							.def(self + other<sf::Int8>())
							.def(self + other<sf::Uint8>())
							.def(self + other<sf::Int16>())
							.def(self + other<sf::Uint16>())
							.def(self + other<sf::Int32>())
							.def(self + other<sf::Uint32>())
							.def(self + float())
							.def(self + double())
							.def(self + char())
							//.def(self + other<std::string>())
							//.def(self + wchar_t())
							//.def(self + other<std::wstring>())
							//.def(self + other<sf::String>())

							.def(self - bool())
							.def(self - other<sf::Int8>())
							.def(self - other<sf::Uint8>())
							.def(self - other<sf::Int16>())
							.def(self - other<sf::Uint16>())
							.def(self - other<sf::Int32>())
							.def(self - other<sf::Uint32>())
							.def(self - float())
							.def(self - double())
							.def(self - char())
							//.def(self - other<std::string>())
							//.def(self - wchar_t())
							//.def(self - other<std::wstring>())
							//.def(self - other<sf::String>())
					];
			}

			void BSocket(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Socket>("Socket")
							.def("SetBlocking", &sf::Socket::SetBlocking)
							.def("IsBlocking", &sf::Socket::IsBlocking)
					];

				object status = newtable(lua);
				status["Done"] = sf::Socket::Done;
				status["NotReady"] = sf::Socket::NotReady;
				status["Disconnected"] = sf::Socket::Disconnected;
				status["Error"] = sf::Socket::Error;
				globals(lua)[ns.c_str()]["Socket"]["Status"] = status;

				globals(lua)[ns.c_str()]["Socket"]["AnyPort"] = sf::Socket::AnyPort;
			}
				
			void BSocketSelector(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::SocketSelector>("SocketSelector")
							.def(constructor<>())
							.def(constructor<const sf::SocketSelector&>())
							.def("Add", &sf::SocketSelector::Add)
							.def("Remove", &sf::SocketSelector::Remove)
							.def("Clear", &sf::SocketSelector::Clear)
							.def("Wait", &sf::SocketSelector::Wait)
							.def("IsReady", &sf::SocketSelector::IsReady)
					];
			//SelectorBase
			//Selector
			}

			void BTcpListener(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::TcpListener, bases<sf::Socket> >("TcpListener")
							.enum_("unnamed")
								[
									value("AnyPort", sf::TcpListener::AnyPort)
								]
							.def(constructor<>())
							.def("GetLocalPort", &sf::TcpListener::GetLocalPort)
							.def("Listen", &sf::TcpListener::Listen)
							.def("Accept", &sf::TcpListener::Accept)
							.def("SetBlocking", &sf::TcpListener::SetBlocking)
							.def("IsBlocking", &sf::TcpListener::IsBlocking)
					];

				object status = newtable(lua);
				status["Done"] = sf::TcpListener::Status::Done;
				status["NotReady"] = sf::TcpListener::Status::NotReady;
				status["Disconnected"] = sf::TcpListener::Status::Disconnected;
				status["Error"] = sf::TcpListener::Status::Error;
				globals(lua)[ns.c_str()]["TcpListener"]["Status"] = status;
			}
				
			void BTcpSocket(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::TcpSocket, bases<sf::Socket> >("TcpSocket")
							.enum_("unnamed")
								[
									value("AnyPort", sf::TcpSocket::AnyPort)
								]
							.def(constructor<>())
							.def("GetLocalPort", &sf::TcpSocket::GetLocalPort)
							.def("GetRemoteAddress", &sf::TcpSocket::GetRemoteAddress)
							.def("GetRemotePort", &sf::TcpSocket::GetRemotePort)
							.def("Connect", &sf::TcpSocket::Connect)
							.def("Disconnect", &sf::TcpSocket::Disconnect)
							.def("Send", (sf::TcpSocket::Status(sf::TcpSocket::*)(const char*, std::size_t))&sf::TcpSocket::Send)
							.def("Send", (sf::TcpSocket::Status(sf::TcpSocket::*)(sf::Packet&))&sf::TcpSocket::Send)
							/*.def("Receive", (sf::TcpSocket::Status(sf::TcpSocket::*)(char*, std::size_t, std::size_t&))&sf::TcpSocket::Receive)*/
							.def("Receive", (sf::TcpSocket::Status(sf::TcpSocket::*)(sf::Packet&))&sf::TcpSocket::Receive)
							.def("SetBlocking", &sf::TcpSocket::SetBlocking)
							.def("IsBlocking", &sf::TcpSocket::IsBlocking)
					];

				object status = newtable(lua);
				status["Done"] = sf::TcpSocket::Status::Done;
				status["NotReady"] = sf::TcpSocket::Status::NotReady;
				status["Disconnected"] = sf::TcpSocket::Status::Disconnected;
				status["Error"] = sf::TcpSocket::Status::Error;
				globals(lua)[ns.c_str()]["TcpSocket"]["Status"] = status;
			}
				
			void BUdpSocket(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::UdpSocket, bases<sf::Socket> >("UdpSocket")
							.enum_("unnamed")
								[
									value("MaxDatagramSize", sf::UdpSocket::MaxDatagramSize)
								]
							.enum_("unnamed2")
								[
									value("AnyPort", sf::UdpSocket::AnyPort)
								]
							.def(constructor<>())
							.def("GetLocalPort", &sf::UdpSocket::GetLocalPort)
							.def("Bind", &sf::UdpSocket::Bind)
							.def("Unbind", &sf::UdpSocket::Unbind)
							/*.def("Send", (sf::UdpSocket::Status(sf::UdpSocket::*)(const char*, std::size_t, const sf::IpAddress&, unsigned short))&sf::UdpSocket::Send)
							.def("Send", (sf::UdpSocket::Status(sf::UdpSocket::*)(sf::Packet&, const sf::IpAddress&, unsigned short))&sf::UdpSocket::Send)
							.def("Receive", (sf::UdpSocket::Status(sf::UdpSocket::*)(char*, std::size_t, std::size_t&, sf::IpAddress&, unsigned short&))&sf::UdpSocket::Receive)
							.def("Receive", (sf::UdpSocket::Status(sf::UdpSocket::*)(sf::Packet&, sf::IpAddress&, unsigned short&))&sf::UdpSocket::Receive)*/
							.def("SetBlocking", &sf::UdpSocket::SetBlocking)
							.def("IsBlocking", &sf::UdpSocket::IsBlocking)
					];

				object status = newtable(lua);
				status["Done"] = sf::UdpSocket::Status::Done;
				status["NotReady"] = sf::UdpSocket::Status::NotReady;
				status["Disconnected"] = sf::UdpSocket::Status::Disconnected;
				status["Error"] = sf::UdpSocket::Status::Error;
				globals(lua)[ns.c_str()]["UdpSocket"]["Status"] = status;
			}
				
			void Bind(lua_State* lua, const std::string& ns)
			{
				open(lua);
				BFtp(lua, ns);
				BHttp(lua, ns);
				BIpAddress(lua, ns);
				BPacket(lua, ns);
				BSocket(lua, ns);
				BSocketSelector(lua, ns);
				BTcpListener(lua, ns);
				BTcpSocket(lua, ns);
				BUdpSocket(lua, ns);
			}
		}
	}
}